// PlayerSkills.h

// Tato trieda definuje schopnosti hraca, ktore sa potom vyuziju pri taktizovani.

#ifndef PLAYERSKILLS_H
#define PLAYERSKILLS_H

#include "Player/PlayerKernel.h"
#include "Common/Interfaces/Commands.h"
//#include "Common/World/Point.h"
//#include "Common/Main.h"
#include "Common/Support/List.h"
#include "FCFarmari/Network.h"

/* -------- FC_Farmari -------- */

// Dlzka trvania trenovania siete
#define	TRAINING_DURATION	50

// Pozicie, kde vo vstupnom vektore siete sa nachadzaju ktore hodnoty.
#define DRIBBLE_NET_INPUT	14

#define	DRIBBLE_DASH	4
#define	DRIBBLE_DASH_POWER	7
#define	DRIBBLE_KICK	6
#define	DRIBBLE_KICK_ANGLE	10
#define	DRIBBLE_KICK_POWER	9
#define	DRIBBLE_TURN	5
#define	DRIBBLE_TURN_ANGLE	8
/* ----------------------------- */

#define POS_TOL 1.0f

//#define CATCH_DBGN DBGN
#define CATCH_DBGN DO_NOTHING

//#define SHOUT_DBGN DBGN
#define SHOUT_DBGN DO_NOTHING

//#define SKILLS_DBGN DBGN
#define SKILLS_DBGN DO_NOTHING

//#define UBLK_DBGN DBGN
#define UBLK_DBGN DO_NOTHING

// Uloha hraca -> brankar alebo regularny hrac.
enum PlayerRole
{
	PR_Goalie,
	PR_Player
};


// Trieda zastresujuca najdolezitejsie schopnosti hraca
class PlayerSkills : public PlayerKernel
{
	// Rozhranie na generator prikazov
	CommandsInterface* m_pCommandGen;

	// Mozeme kopnut do lopty?
	bool m_bKickable;

	// Vektor od hraca k lopte
	Vector m_BallDiff;

	// Vzdielnost medzi loptou a hracom (nemusi byt ta ista ako m_BallDiff!)
	float m_fBallDistance;
		
	// Posledny cyklus, ked hrac otocil krkom.
	int m_iTimeOfLTurnNeck;

	// Pomocna metoda pre driblovanie
	bool DribbleRun(float);

	// Kopne loptu na urcite miesto
	void NearKick(const Point&);

protected:
	// Rozhodovanie sa mimo modu play_on (cas je zastaveny).		
	virtual void RunPlayOff();

	// Rozhodovanie sa pocas modu play_on.	
	virtual void RunPlayOn();


	// ATRIBUTY:
	//
	int m_iGoalieCatchBan;

	// Rola hraca
	PlayerRole m_PlayerRole;
	

	// CHOVANIE SA HRACA V ROZNYCH SITUACIACH (tieto metody su pretazene v PlayerTactics)
	// --------------------------------------
	virtual void BehaveWithBall() {}
	virtual void BehaveWithoutBall() {}
	virtual void BehaveWithBallGoalie() {}
	virtual void BehaveWithoutBallGoalie() {}
#ifdef GOALIE
	virtual void BehaveWithoutBallKnowledgeGoalie() {}
	virtual void LPT_Main() {}
	bool lpt_goalie;
#endif


	// BEHACIE (PRESUVACIE) METODY
	// ---------------------------
	// Presun sa na urcity bod (skokova metoda)
	void MoveTo(const Point&);

	// Bezi na zadanu poziciu, na ktorej ocakava najvhodnejsie zachytenie lopty 
	void RunToBallInteceptPosition(Point pos);

	// Bez na poziciu
	void RunToPoint(const Point& target, bool hurry, bool forLife = false, float posTol = POS_TOL, int angTol = 10);
	// Bez na zadnu poziciu celom vpred (pre brankara)
	void RunToPointBackwards(const Point& target, bool hurry, bool forLife = false, float posTol = POS_TOL, int angTol = 10);

	// Bezi na poziciu zadanu na vstupe istou rychlostou
	void RunToPosition(Point position, int nSpeedMode);


	// CHYTACIE METODY
	// ---------------
	// Dokazeme chytit loptu?
	bool CanCatchBall() const;
	bool LPT_CanCatchBall(float catch_coef,const Point& myFuturePos,const Point& ballFuturePos,int cycles) const;

	// Chyti loptu
	void CatchBall();
	

	// DRIBLOVACIE METODY
	// ------------------
	// 1. sposob driblovania
	void DribbleTo(const Point&);
	// 2. sposob driblovania
	void DribbleTo2(const Point&, float angle = 0,  bool bFast = false);


	// KOPACIE METODY
	// --------------

	// Vykopnutie lopty celou silou na ciel
	void DumbKick(const Point&);

	// Da sa kopnut do lopty?
	bool IsBallKickAble() const
	{
		return m_bKickable;
	}

	// Vykopnutie na branku 1
	// void KickToGoal();
	// Vykopnutie na branku 2 (presnejsie do stredu branky)
	void KickToGoal2();
	// Vykopnutie na branku 3 (lepsie)
	void KickToGoal3();
	// Vykopnutie na branku 4 - vyuziva sa pritom gradientova mapa (najlepsie)
	void KickToGoal4();
	// Vykopnutie na branku od Loptosov - v jednoduchosti je krasa
	void LPT_KickToGoal();
	
		// Mam kopnut do lopty mimo modu PlayOn?
	virtual bool ShouldKickIn();

	// Je mozne kopnut do lopty? (Malo by sa nad tym vobec uvazovat z hladiska sucasneho herneho modu?)
	bool SomeoneShouldKickIn();


	// KRKOVE METODY
	// --------------	
	// Zarovnaj krk s telom (relativny uhol medzi krkom a telom je 0 stupnov)
	void AlignNeck();

	// Tato metoda synchronizuje krkove metody s prichadzajucou vizualnou informaciou
	void NeckSynchronizationWithVI(int nMode);

	// Otoc krk na urcite miesto
	void TurnNeckTo(const Point& future_pos, const Point& future_mypos, float fNextTurn = 0);
	void TurnNeckToAux(float fCorrection = 0);	


	// NAHRAVACIE METODY
	// -----------------
	
	// Zadana rychlost sa prekalkuluje tak, aby bola podla vzorca brana do uvahy aj vzidalenost a natocenie hraca,
	// ked prihrava
	float CorrectPassSpeed(float fRequirSpeeed);
	// Predkopnutie lopty cez hranicu offsajdu
	void OffsideLineBreach(float offsideLine);
	// Nahra loptu na urcite miesto
	void PassBallTo(const Point& pos, float fRem_spd = 0.7f);
	// Nahra loptu hracovi
	void PassBallToPlayer(const Player& player, float spd = 0.7f);
	// Vykopnutie lopty z celej sily na superovu branu
	void PassToRandomUmbrellaPosition();
	// Vykopnutie lopty z celej sily na strategicku poziciu
	void PassToStrategicPosition();


	// SMYKACKOVE METODY
	// -----------------
	// Dokazeme smykackou vypichnut loptu?
	bool CanTackleBall() const;

	// Urob smykacku
	void Tackle(const float);
	

	// ZACHYTAVACIE METODY
	// -------------------
	
	// Vrati optimalny bod pre zachytenie prihravky
	Point GetBallInterceptionPoint();
	
	// Zachyti loptu ak je to mozne. Vracia false ak to nie je mozne.
	bool InterceptBall();

	// Zisti, ci lopta je v danom cykle na dosah hraca
	bool IsBallInPlayerKickableAreaDuringInteception(double lfBallDecayInTime, int time);
	
	// Mal by hrac vobec uvazovat nad zachytenim lopty?
	bool ShouldInterceptBall();

	// Mal by som bezat za loptou? Som za nu zodpovedny?
	bool DependentForBall() const;
	
	// Vrati supera najblizsieho k lopte.
	int NearEnemy(int* pCycles) const;
	
	// Vrati naseho najblizsieho hraca k lopte. Vrati -1, ak som to ja. 
	int NearFriend(int* pCycles) const;
	

	// PREDIKOVACIE METODY PO PRIKAZOCH
	Myself LPT_AfterDash(const Myself& me,float DashPower) const;
	Myself LPT_AfterTurn(const Myself& me,float Moment) const;

	// ZVYSNE METODY
	// -------------
	
	// zmena pohadu brankara
	void LPT_GoalieSetView();

	// Rozhodovanie sa
	virtual void Act();

	// Najdi svoju domovsku poziciu pred vykopnutim.
	virtual Point GetHomePos()
	{
		return Point();
	}

	// Vrati poziciu ofsajdovej ciary
	float GetOffsideLine() const;

	// Je dany bod medzi bodmi p1 a p2?
	bool InTheMiddle(const Point& tested, const Point& p1, const Point& p2) const;

	// Nachadza sa hrac na (alebo blizko) svojej domovskej pozicii?
	bool NearHomePosition();
	
	// Predikuje rychlost v dalsom kroku
	Vector PredictNextVel(float DashPower) const;
	Vector LPT_PredictNextVel(float DashPower,const Myself &me) const;

	// Otacaj sa zatial co hladas loptu, alebo nieco ine.
	float Scan();

	// Zmeni uhol pohladu
	void SetView(const ViewWidth);

	// Kopnutim sa natoci lopta
	void TurnBall();

	// Sluzi na transformovanie pohladu hraca, tak aby sa pribezne obzeral vlavo, dopredu a vpravo
	void TransformLookDirection(Point& pointDirection);

	// Natoci telo na urcity bod
	void TurnTo(const Point&);
	

	// POSIELANIE SPRAV
	// ----------------
	// Posiela zvukovu informaciu
	void SendInfo();
	// Mal by som poslat zvukovu informaciu?
	bool ShouldSendInfo();
	
	
public:

	// Body, do ktorych si uklada funkcia TurnNeckTo docasne parametre.
	Point TurnNeckTo_futurePos;
	Point TurnNeckTo_futureMyPos;
	float TurnNeckTo_nextTurn;
	int nNeckDirection;
	bool bAvoidNextCorrection;
	int nChangeView;

	enum NeckDirection
	{
		LEFT = 1, FRONT, RIGHT
	};

	NeckDirection eActualNeckDirection, ePreviousNeckDirection;
	
	// Bod pre strlebu, ktory sa pouziva nielen pre urcenie optimalneho bodu pre strelbu
	double lfShootPosX, lfShootPosY;

	// Konstruktor
	PlayerSkills(const char* name = "PlayerSkills", const char* desc = "PlayerKernel(PlayerSkills) module");
	
	// Destruktor
	virtual ~PlayerSkills();

	// Inicializacia rozhrania
	virtual int Init(int argc, char** argv, int iTask);

	// Pretazene metody z PlayerKernel
	virtual void OnInit(RealSide realSide, int uniform, PlayMode mode);
	virtual void OnHear(int time, float direction, bool ourTeam, int uniform, const char* msg);

	// Zisti, ci je bod v obldzniku
	bool IsPointInRectArea(double lfPointX, double lfPointY, double lfLeft, double lfTop, double lfRight, double lfBottom);

	//
	float CalcRealSpeedMax() const;

	// Kompenzovanie momentu zotrvacnosti
	float CompMoment(float) const;

	// Kompenzovanie momentu otacania
	float CompTurn(float) const;

	// Vrati hernu rolu hraca
	PlayerRole GetPlayerRole() const
	{
		return m_PlayerRole;
	}

//vrati rozhranie na posielanie prikazov 

	CommandsInterface* getCommGen(){
		return m_pCommandGen;
	}

	// Kolko krokov je potrebnych na prebehnutie danej vzdialenosti?
	int PredictSteps(float fDist, float fPower, float fActSpeed = 0) const;

	// Vypocita doporuceny maximalny koeficient sprintu
	float RecommDashPower(bool bFast, bool bReallyFast = false) const;
	//
	float RecommendDashToMaxSpeed() const;

	// Nastavi hernu rolu hraca
	void SetPlayerRole(PlayerRole role)
	{
		m_PlayerRole = role;
	}
	
	// Vrati pozorovaci uhol v zavislosti na vzdialenosti
	ViewWidth WidthFromDistance(float) const;
 	
// --------------------- FC Farmari ---------------------
	
private:
	FCNetwork *m_pFCDribbleNet;

	int FCEvaluateInputs(FCNetwork *net, int N, double **Inputs);
	void FCDribblePerformActions(double *Input);
	void FCFixDribbleWeights(const Point& Target);
	void FCGetDribbleInputs(int &N, double **&Input);
	
protected:
	Point	FCTarget;
	Point	FCPSource;
	Point	FCBSource;
	int		FCTime;
	int		FCDurTime;
	int		FCWriteTime;
	int		FCDiffTime;

public:	
	// Treba zadefinovat Target bod v pripade trenovania siete a tiez cas,
	// za ktory sa ma dostat na misto, tiez v pripade trenovania
	void FCDribbleTo(const Point& Target);
	
	void FCSetViewWidth(ViewWidth iWidth);

// V pripade trenovania potrebujem tuto funkciu...
#ifdef TRAINING
// Ak totiz trenujem tak v tejto metode budem odchytavat zmeny hracich modov a prislusne ich budem obsluhovat
	virtual void OnChangeMode(int time, PlayMode mode);
#endif

	bool FCBelongsToArea(Point A, Point B, Point E);
	void FCGetDistances(Point A, Point B, Point E, double* result);

protected:

	// NASLEDNE FUNKCIE NIE SU PLNE FUNKCNE, JE VHODNE ICH PREPRACOVAT

	// Struktura, ktora v sebe obsahuje rozdiely medzi vsetkymi hracmi a loptou.
	// Pouziva sa na uchovanie vysledkov simulacie drahy lopty
	class CatchSimData
	{
	private:
		// 
		float myDif;
		//
		int enemyCnt;
		//
		float* enemyDifs;
		// 
		int friendCnt;
		//
		float* friendDifs;
	
	public:

		Point ballPos;
		
		// Konstruktor
		inline CatchSimData(int fc, int ec);

		// Destruktor
		~CatchSimData()
		{
			free(friendDifs);
			free(enemyDifs);
		}

		//
		int GetFriendCnt()
		{
			return friendCnt;
		}
		//
		int GetEnemyCnt()
		{
			return enemyCnt;
		}
		
		//
		float GetEnemyDif(int i)
		{
			return enemyDifs[i];
		}
		//
		void SetEnemyDif(int i, float d)
		{
			enemyDifs[i] = d;
		}
		
		//
		float GetFriendDif(int i)
		{
			return friendDifs[i];
		}
		//
		void SetFriendDif(int i, float d)
		{
			friendDifs[i] = d;
		}
		
		//
		float GetMyDif()
		{
			return myDif;
		}
		//
		void SetMyDif(float d)
		{
			myDif = d;
		}
	}; // class CatchSimData

	// Zisti sa, ci moze hrac zachytit loptu. Ak moze, zisti sa kam ma bezat.
	bool CanInterceptBall(Point* point);
	// Pomocna funkcia pre CanInterceptBall -> vyhodnocuje simulacne udaje
	bool CatchEvaluateData(Point* point, List<CatchSimData> * input);
	// Pomocna funkcia pre CanInterceptBall -> simuluje drahu lopty
	void CatchSimBallPath(List<CatchSimData> * output);
	// Pomocna funkcia pre CanInterceptBall -> simuluje jedneho hraca v nasledujucom cykle
	void CatchSimRunningPlayer(float dashPower, float* speed, float* distance);

 };

 // Konstruktor
PlayerSkills::CatchSimData::CatchSimData(int fc, int ec)
{
	friendCnt = fc; 
	enemyCnt = ec;
	friendDifs = (float*) malloc(sizeof(float) * fc);
	enemyDifs = (float*) malloc(sizeof(float) * ec);
}

#endif // PLAYERSKILLS_H
